[XEN][POWERPC] Find all of memory and feed all the heaps
authorJimi Xenidis <jimix@watson.ibm.com>
Tue, 22 Aug 2006 21:20:58 +0000 (17:20 -0400)
committerJimi Xenidis <jimix@watson.ibm.com>
Tue, 22 Aug 2006 21:20:58 +0000 (17:20 -0400)
This code walks the OF dev tree, finding end-of-memory and memory holes.
All memory beyond the hypervisor's RMA is added to domheap. (Previously
only memory upto 1st hole was used.) Finally, parts of setup.c have been
swept into memory.c as cleanup.

Based on a patch by Dan Poff <poff@us.ibm.com>.

Signed-off-by: Jimi Xenidis <jimix@watson.ibm.com>
Signed-off-by: Hollis Blanchard <hollisb@us.ibm.com>
xen/arch/powerpc/Makefile
xen/arch/powerpc/exceptions.h
xen/arch/powerpc/memory.c [new file with mode: 0644]
xen/arch/powerpc/oftree.h
xen/arch/powerpc/setup.c

index b17730832b8c09da422a5b26ecfe8d2b3830f3de..98ffab027cfd0b08b3599058963b62e5bd89a0c9 100644 (file)
@@ -23,6 +23,7 @@ obj-y += htab.o
 obj-y += iommu.o
 obj-y += irq.o
 obj-y += mambo.o
+obj-y += memory.o
 obj-y += mm.o
 obj-y += mpic.o
 obj-y += mpic_init.o
index 25ffc1ace77809ad56bb8a56b64e1111b79a1ebd..2294a585712c4f9d99feb693ecebb4b78cadfb40 100644 (file)
@@ -51,7 +51,4 @@ extern ulong *__hypercall_table[];
 extern char exception_vectors[];
 extern char exception_vectors_end[];
 extern int spin_start[];
-extern int firmware_image_start[0];
-extern int firmware_image_size[0];
-
 #endif
diff --git a/xen/arch/powerpc/memory.c b/xen/arch/powerpc/memory.c
new file mode 100644 (file)
index 0000000..c862c0f
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Copyright (C) IBM Corp. 2006
+ *
+ * Authors: Dan Poff <poff@us.ibm.com>
+ *          Jimi Xenidis <jimix@watson.ibm.com>
+ */
+#include <xen/sched.h>
+#include <xen/mm.h>
+#include "of-devtree.h"
+#include "oftree.h"
+
+unsigned long xenheap_phys_end;
+struct membuf {
+    ulong start;
+    ulong size;
+};
+
+typedef void (*walk_mem_fn)(struct membuf *, uint);
+
+static ulong free_xenheap(ulong start, ulong end)
+{
+    start = ALIGN_UP(start, PAGE_SIZE);
+    end = ALIGN_DOWN(end, PAGE_SIZE);
+
+    printk("%s: 0x%lx - 0x%lx\n", __func__, start, end);
+
+    if (oftree <= end && oftree >= start) {
+        printk("%s:     Go around the devtree: 0x%lx - 0x%lx\n",
+               __func__, oftree, oftree_end);
+        init_xenheap_pages(start, ALIGN_DOWN(oftree, PAGE_SIZE));
+        init_xenheap_pages(ALIGN_UP(oftree_end, PAGE_SIZE), end);
+    } else {
+        init_xenheap_pages(start, end);
+    }
+
+    return ALIGN_UP(end, PAGE_SIZE);
+}
+
+static void set_max_page(struct membuf *mb, uint entries)
+{
+    int i;
+
+    for (i = 0; i < entries; i++) {
+        ulong end_page;
+
+        end_page = (mb[i].start + mb[i].size) >> PAGE_SHIFT;
+
+        if (end_page > max_page)
+            max_page = end_page;
+    }
+}
+
+/* mark all memory from modules onward as unused, skipping hole(s),
+ * and returning size of hole(s) */
+static void heap_init(struct membuf *mb, uint entries)
+{
+    int i;
+    ulong start_blk;
+    ulong end_blk = 0;
+
+       for (i = 0; i < entries; i++) {
+           start_blk = mb[i].start;
+           end_blk = start_blk + mb[i].size;
+
+           if (start_blk < xenheap_phys_end) {
+            if (xenheap_phys_end > end_blk) {
+                panic("xenheap spans LMB\n");
+            }
+            if (xenheap_phys_end == end_blk)
+                continue;
+
+            start_blk = xenheap_phys_end;
+        }
+
+        init_boot_pages(start_blk, end_blk);
+        total_pages += (end_blk - start_blk) >> PAGE_SHIFT;
+       }
+}
+
+static void ofd_walk_mem(void *m, walk_mem_fn fn)
+{
+    ofdn_t n;
+    uint p_len;
+    struct membuf mb[8];
+    static char name[] = "memory";
+
+    n = ofd_node_find_by_prop(m, OFD_ROOT, "device_type", name, sizeof(name));
+    while (n > 0) {
+
+        p_len = ofd_getprop(m, n, "reg", mb, sizeof (mb));
+        if (p_len <= 0) {
+            panic("ofd_getprop(): failed\n");
+        }
+        if (p_len > sizeof(mb))
+            panic("%s: buffer is not big enuff for this firmware: "
+                  "0x%lx < 0x%x\n", __func__, sizeof(mb), p_len);
+
+        fn(mb, p_len / sizeof(mb[0]));
+        n = ofd_node_find_next(m, n);
+    }
+}
+
+static void setup_xenheap(module_t *mod, int mcount)
+{
+    int i;
+    ulong freemem;
+
+    freemem = ALIGN_UP((ulong)_end, PAGE_SIZE);
+
+    for (i = 0; i < mcount; i++) {
+        u32 s;
+
+        if(mod[i].mod_end == mod[i].mod_start)
+            continue;
+
+        s = ALIGN_DOWN(mod[i].mod_start, PAGE_SIZE);
+
+        if (mod[i].mod_start > (ulong)_start &&
+            mod[i].mod_start < (ulong)_end) {
+            /* mod was linked in */
+            continue;
+        }
+
+        if (s < freemem) 
+            panic("module addresses must assend\n");
+
+        free_xenheap(freemem, s);
+        freemem = ALIGN_UP(mod[i].mod_end, PAGE_SIZE);
+        
+    }
+
+    /* the rest of the xenheap, starting at the end of modules */
+    free_xenheap(freemem, xenheap_phys_end);
+}
+
+void memory_init(module_t *mod, int mcount)
+{
+    ulong eomem;
+    ulong heap_start, heap_size;
+
+    printk("Physical RAM map:\n");
+
+    /* lets find out how much memory there is and set max_page */
+    max_page = 0;
+    ofd_walk_mem((void *)oftree, set_max_page);
+    eomem = max_page << PAGE_SHIFT;
+
+    if (eomem == 0){
+        panic("ofd_walk_mem() failed\n");
+    }
+    printk("End of RAM: %luMB (%lukB)\n", eomem >> 20, eomem >> 10);
+
+    /* Architecturally the first 4 pages are exception hendlers, we
+     * will also be copying down some code there */
+    heap_start = 4 << PAGE_SHIFT;
+    if (oftree < (ulong)_start)
+        heap_start = ALIGN_UP(oftree_end, PAGE_SIZE);
+
+    heap_start = init_boot_allocator(heap_start);
+    if (heap_start > (ulong)_start) {
+        panic("space below _start (%p) is not enough memory "
+              "for heap (0x%lx)\n", _start, heap_start);
+    }
+
+    /* we give the first RMA to the hypervisor */
+    xenheap_phys_end = rma_size(cpu_rma_order());
+
+    /* allow everything else to be allocated */
+    total_pages = 0;
+    ofd_walk_mem((void *)oftree, heap_init);
+    if (total_pages == 0)
+        panic("heap_init: failed");
+
+    if (total_pages > max_page)
+        panic("total_pages > max_page: 0x%lx > 0x%lx\n",
+              total_pages, max_page);
+
+    printk("total_pages: 0x%016lx\n", total_pages);
+
+    init_frametable();
+    end_boot_allocator();
+
+    /* Add memory between the beginning of the heap and the beginning
+     * of out text */
+    free_xenheap(heap_start, (ulong)_start);
+
+    heap_size = xenheap_phys_end - heap_start;
+    printk("Xen heap: %luMB (%lukB)\n", heap_size >> 20, heap_size >> 10);
+
+    setup_xenheap(mod, mcount);
+
+    eomem = avail_domheap_pages();
+    printk("Domheap pages: 0x%lx %luMB (%lukB)\n", eomem,
+           (eomem << PAGE_SHIFT) >> 20,
+           (eomem << PAGE_SHIFT) >> 10);
+}
index 4a96ceb3d0a2e83938edf7dbb759b7e69f6f8cc0..bf1f210665b78b53816e04e9257f207317372555 100644 (file)
 
 #ifndef _OFTREE_H
 #define _OFTREE_H
+#include <xen/multiboot.h>
 
 extern ulong oftree;
 extern ulong oftree_len;
+extern ulong oftree_end;
 
 extern int ofd_dom0_fixup(
     struct domain *d, ulong mem, start_info_t *si, ulong dst);
@@ -30,4 +32,6 @@ extern int ofd_dom0_fixup(
 extern int firmware_image_start[0];
 extern int firmware_image_size[0];
 
+extern void memory_init(module_t *mod, int mcount);
+
 #endif  /* #ifndef _OFTREE_H */
index 15398309f371adb13e5c942aabe5d93993e6b64e..7234dc0cbfb331f038d52ecdf6889e50a52e8a4a 100644 (file)
@@ -43,9 +43,9 @@
 #include <asm/percpu.h>
 #include "exceptions.h"
 #include "of-devtree.h"
+#include "oftree.h"
 
 #define DEBUG
-unsigned long xenheap_phys_end;
 
 /* opt_noht: If true, Hyperthreading is ignored. */
 int opt_noht = 0;
@@ -220,24 +220,6 @@ void startup_cpu_idle_loop(void)
     reset_stack_and_jump(idle_loop);
 }
 
-static ulong free_xenheap(ulong start, ulong end)
-{
-    start = ALIGN_UP(start, PAGE_SIZE);
-    end = ALIGN_DOWN(end, PAGE_SIZE);
-
-    printk("%s: 0x%lx - 0x%lx\n", __func__, start, end);
-
-    if (oftree <= end && oftree >= start) {
-        printk("%s:     Go around the devtree: 0x%lx - 0x%lx\n",
-                  __func__, oftree, oftree_end);
-        init_xenheap_pages(start, ALIGN_DOWN(oftree, PAGE_SIZE));
-        init_xenheap_pages(ALIGN_UP(oftree_end, PAGE_SIZE), end);
-    } else {
-        init_xenheap_pages(start, end);
-    }
-    return ALIGN_UP(end, PAGE_SIZE);
-}
-
 static void init_parea(int cpuid)
 {
     /* Be careful not to shadow the global variable.  */
@@ -289,15 +271,8 @@ static void __init __start_xen(multiboot_info_t *mbi)
 {
     char *cmdline;
     module_t *mod = (module_t *)((ulong)mbi->mods_addr);
-    ulong heap_start;
-    ulong eomem = 0;
-    ulong heap_size = 0;
-    ulong bytes = 0;
-    ulong freemem;
     ulong dom0_start, dom0_len;
     ulong initrd_start, initrd_len;
-    
-    int i;
 
     memcpy(0, exception_vectors, exception_vectors_end - exception_vectors);
     synchronize_caches(0, exception_vectors_end - exception_vectors);
@@ -339,88 +314,7 @@ static void __init __start_xen(multiboot_info_t *mbi)
     mod[mbi->mods_count-1].mod_end = 0;
     --mbi->mods_count;
 
-    printk("Physical RAM map:\n");
-
-    /* lets find out how much memory there is */
-    while (bytes < mbi->mmap_length) {
-        u64 end;
-        u64 addr;
-        u64 size;
-
-        memory_map_t *map = (memory_map_t *)((ulong)mbi->mmap_addr + bytes);
-        addr = ((u64)map->base_addr_high << 32) | (u64)map->base_addr_low;
-        size = ((u64)map->length_high << 32) | (u64)map->length_low;
-        end = addr + size;
-
-        printk(" %016lx - %016lx (usable)\n", addr, end);
-
-        if (addr > eomem) {
-            printk("found a hole skipping remainder of memory at:\n"
-                   " %016lx and beyond\n", addr);
-            break;
-        }
-        if (end > eomem) {
-            eomem = end;
-        }
-        bytes += map->size + 4;
-    }
-
-    printk("System RAM: %luMB (%lukB)\n", eomem >> 20, eomem >> 10);
-
-    /* top of memory */
-    max_page = PFN_DOWN(ALIGN_DOWN(eomem, PAGE_SIZE));
-    total_pages = max_page;
-
-    /* Architecturally the first 4 pages are exception hendlers, we
-     * will also be copying down some code there */
-    heap_start = 4 << PAGE_SHIFT;
-    if (oftree < (ulong)_start)
-        heap_start = ALIGN_UP(oftree_end, PAGE_SIZE);
-
-    heap_start = init_boot_allocator(heap_start);
-    if (heap_start > (ulong)_start) {
-        panic("space below _start (%p) is not enough memory "
-              "for heap (0x%lx)\n", _start, heap_start);
-    }
-
-    /* we give the first RMA to the hypervisor */
-    xenheap_phys_end = rma_size(cpu_rma_order());
-
-    /* allow everything else to be allocated */
-    init_boot_pages(xenheap_phys_end, eomem);
-    init_frametable();
-    end_boot_allocator();
-
-    /* Add memory between the beginning of the heap and the beginning
-     * of out text */
-    free_xenheap(heap_start, (ulong)_start);
-    freemem = ALIGN_UP((ulong)_end, PAGE_SIZE);
-
-    for (i = 0; i < mbi->mods_count; i++) {
-        u32 s;
-
-        if(mod[i].mod_end == mod[i].mod_start)
-            continue;
-
-        s = ALIGN_DOWN(mod[i].mod_start, PAGE_SIZE);
-
-        if (mod[i].mod_start > (ulong)_start &&
-            mod[i].mod_start < (ulong)_end) {
-            /* mod was linked in */
-            continue;
-        }
-
-        if (s < freemem) 
-            panic("module addresses must assend\n");
-
-        free_xenheap(freemem, s);
-        freemem = ALIGN_UP(mod[i].mod_end, PAGE_SIZE);
-        
-    }
-
-    /* the rest of the xenheap, starting at the end of modules */
-    free_xenheap(freemem, xenheap_phys_end);
-
+    memory_init(mod, mbi->mods_count);
 
 #ifdef OF_DEBUG
     printk("ofdump:\n");
@@ -428,10 +322,6 @@ static void __init __start_xen(multiboot_info_t *mbi)
     ofd_walk((void *)oftree, OFD_ROOT, ofd_dump_props, OFD_DUMP_ALL);
 #endif
 
-    heap_size = xenheap_phys_end - heap_start;
-
-    printk("Xen heap: %luMB (%lukB)\n", heap_size >> 20, heap_size >> 10);
-
     percpu_init_areas();
 
     init_parea(0);
@@ -484,10 +374,10 @@ static void __init __start_xen(multiboot_info_t *mbi)
         panic("Could not set up DOM0 guest OS\n");
     }
 
-    free_xenheap(ALIGN_UP(dom0_start, PAGE_SIZE),
+    init_xenheap_pages(ALIGN_UP(dom0_start, PAGE_SIZE),
                  ALIGN_DOWN(dom0_start + dom0_len, PAGE_SIZE));
     if (initrd_start)
-        free_xenheap(ALIGN_UP(initrd_start, PAGE_SIZE),
+        init_xenheap_pages(ALIGN_UP(initrd_start, PAGE_SIZE),
                      ALIGN_DOWN(initrd_start + initrd_len, PAGE_SIZE));
 
     init_trace_bufs();